#pragma once

#include "cppmicroservices/logservice/LogService.hpp"
#include "cppmicroservices/logservice/Logger.hpp"
#include "cppmicroservices/logservice/LoggerFactory.hpp"
#include <cppmicroservices/Bundle.h>
#include <cppmicroservices/BundleContext.h>

#include <memory>
#include <mutex>
#include <string>
#include <map>

using namespace cppmicroservices::logservice;
using namespace cppmicroservices;

namespace usk {
    namespace core {
        class USKLogserviceImplPrivate;

        class USKLogserviceImpl : public cppmicroservices::logservice::LogService {
        public:
            explicit USKLogserviceImpl(std::string const &loggerName);

            ~USKLogserviceImpl() override = default;

            void Log(SeverityLevel level, std::string const &message) override;

            void Log(SeverityLevel level, std::string const &message,
                     const std::exception_ptr ex) override;

            void Log(ServiceReferenceBase const &sr, SeverityLevel level,
                     std::string const &message) override;

            void Log(ServiceReferenceBase const &sr, SeverityLevel level,
                     std::string const &message, const std::exception_ptr ex) override;

            [[nodiscard]] std::shared_ptr<Logger>
            getLogger(std::string const &name) const override;

            [[nodiscard]] std::shared_ptr<Logger>
            getLogger(const cppmicroservices::Bundle &bundle,
                      std::string const &name) const override;

            template<typename... Args>
            void logImpl(SeverityLevel level, Args &&... args) {
                const auto currLogger = std::atomic_load(&GetCurrentLogger());
                if (!currLogger) {
                    return;
                }

                switch (level) {
                    case SeverityLevel::LOG_DEBUG:
                        currLogger->debug(std::forward<Args>(args)...);
                        break;
                    case SeverityLevel::LOG_INFO:
                        currLogger->info(std::forward<Args>(args)...);
                        break;
                    case SeverityLevel::LOG_WARNING:
                        currLogger->warn(std::forward<Args>(args)...);
                        break;
                    case SeverityLevel::LOG_ERROR:
                        currLogger->error(std::forward<Args>(args)...);
                        break;
                    default:
                        currLogger->trace(std::forward<Args>(args)...);
                        break;
                }
            }

        private:
            std::shared_ptr<Logger> GetCurrentLogger() const;

            std::shared_ptr<USKLogserviceImplPrivate> d_;
        };
    } // namespace core
} // namespace usk
